package com.lxy.file.controller;

import com.alibaba.fastjson.JSONObject;
import com.lxy.file.server.FileOperationService;
import com.lxy.file.util.FileUtil;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;


import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Author lxy
 * @Date 2021/12/27 18:42
 * @Description
 */
@RestController
@CrossOrigin
public class TestController {

    @Autowired
    private FileOperationService fileOperationService;

    /**
     checkFileExist接收一个json，通过文件hash值来判断是否需要妙传
     */
    @PostMapping("/checkFileExist")
    public JSONObject checkFileExist(@RequestBody JSONObject data) throws IOException {
        String fileHash = (String) data.get("fileHash");

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("shouldUpload","true");

        String fileLocal = fileOperationService.getFileLocal(fileHash);
        if (fileLocal != null){
            jsonObject.put("shouldUpload",fileLocal);
        }else{
            jsonObject.put("shouldUpload","check_false");
        }
        return jsonObject;
    }

    @PostMapping("/uploadFile")
    public JSONObject uploadFile(MultipartHttpServletRequest mf) throws IOException {
        int fileTarSize = Integer.parseInt(mf.getParameter("size"));
        int sliceSize = FileUtil.PARTFILESIZE;
        String fileHashCode = mf.getParameter("fileHash");
        String fileName = mf.getParameter("filename");
        String seq = mf.getParameter("index"); //分片序号
        System.out.println("文件大小："+fileTarSize+",文件hash："+fileHashCode);
        Integer fileStatus = fileOperationService.checkFileStatus(fileHashCode, fileTarSize);
        if(fileStatus == -1){ //-1代表文件上传出错
            System.out.println("文件上传出错");
            JSONObject resJson = new JSONObject();
            resJson.put("shouldUpload","upload_false");
            return resJson;
        }else{//检测文件发现处于正在上传阶段，那么redis中存储的文件大小+这个包的大小与总大小作对比
            MultipartFile chunk = mf.getFile("chunk");
            JSONObject result = fileOperationService.uploadSlice(chunk, fileName, seq, sliceSize, fileHashCode, fileTarSize);
            return result;
        }
    }

    @RequestMapping(value = "uploadFile1", method = RequestMethod.POST)
    public String uploadFile1(HttpServletRequest request) throws IOException {
        String path = "D:\\testEnvironment\\largeFileUpTestEnvironment\\";
        String mergeFileName = "D:\\testEnvironment\\largeFileUpTestEnvironment\\target\\test.sql";
        int partFileSize = 500;
        MultipartHttpServletRequest multipartRequest=(MultipartHttpServletRequest) request;

        MultipartFile multipartFile1 = multipartRequest.getFile("file1");//file是form-data中二进制字段对应的name
        MultipartFile multipartFile2 = multipartRequest.getFile("file2");//file是form-data中二进制字段对应的name

        File file1 = new File(path+multipartFile1.getOriginalFilename());
        File file2 = new File(path+multipartFile2.getOriginalFilename());

        FileUtils.copyInputStreamToFile(multipartFile1.getInputStream(), file1);
        FileUtils.copyInputStreamToFile(multipartFile1.getInputStream(), file2);

//        String name = multipartFile1.getName();
//        String originalFilename = multipartFile1.getOriginalFilename();
//        String contentType = multipartFile1.getContentType();
//        Resource resource = multipartFile1.getResource();
//        InputStream inputStream = multipartFile1.getInputStream();
//        byte[] bytes = new byte[3000];
//        inputStream.read(bytes);
//        System.out.println("name:"+name);
//        System.out.println("originalFilename:"+originalFilename);
//        System.out.println("contentType:"+contentType);
//        System.out.println("resource"+resource);
//        System.out.println("inputStream"+new String(bytes));
        List<File> partFiles = new ArrayList<>();
        partFiles.add(file1);
        partFiles.add(file2);
        Collections.sort(partFiles, new FileComparator());
        RandomAccessFile ra = new RandomAccessFile(mergeFileName, "rw");
        ra.setLength(multipartFile1.getSize()+multipartFile2.getSize()+100);
        ra.close();

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(partFiles.size(),
                partFiles.size() * 3, 1, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(partFiles.size() * 2));

        for (int i = 0; i < partFiles.size(); i++) {
            threadPool.execute(new MergeRunnable(i * partFileSize,mergeFileName, partFiles.get(i)));
        }
        return " ";
    }

    private static class FileComparator implements Comparator<File> {
        @Override
        public int compare(File o1, File o2) {
            return o1.getName().compareToIgnoreCase(o2.getName());
        }
    }

    private static class MergeRunnable implements Runnable {
        long startPos;//开始写入位置
        String mergeFileName;//写入的文件名
        File partFile;//分片

        public MergeRunnable(long startPos, String mergeFileName, File partFile) {
            this.startPos = startPos;
            this.mergeFileName = mergeFileName;
            this.partFile = partFile;
        }
        public void run() {
            RandomAccessFile rFile;
            try {
                rFile = new RandomAccessFile(mergeFileName, "rw");
                rFile.seek(startPos);
                FileInputStream fs = new FileInputStream(partFile);
                byte[] b = new byte[fs.available()];
                fs.read(b);
                fs.close();
                rFile.write(b);
                rFile.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
